﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using WeifenLuo.WinFormsUI.Docking;
using MacomberMapSystem.Common.Database;
using System.Data.Common;
using System.IO;

namespace MacomberMapSystem.Common.User_Interfaces.One_Lines
{
    /// <summary>
    /// This form displays an audit window that allows users to modify and revert one-lines they had completed
    /// </summary>
    public partial class frmOneLineAudit : DockContent
    {
        #region Variable declarations
        private MM_Database_Connector dbConn;
        private MM_Database_User User;
        private MM_Database_Model Model;
        private MM_Database_Assignment_Sorter Sorter;
        private List<MM_Database_Assignment> Assignments = new List<MM_Database_Assignment>();
        private ContextMenuStrip cms = new ContextMenuStrip();
        #endregion

        #region Initialization
        /// <summary>
        /// Initialize a new one-line audit form
        /// </summary>
        /// <param name="Model"></param>
        /// <param name="dbConn"></param>
        public frmOneLineAudit(MM_Database_Model Model, MM_Database_Connector dbConn)
        {           
            InitializeComponent();
            //Build a list of all completed one-lines (whether with assignment or not) done by our user.                       
            lvEvents.Columns.Add("Element");
            lvEvents.Columns.Add("Assigned to");
            lvEvents.Columns.Add("Completed by");
            lvEvents.Columns.Add("Completed on");
            lvEvents.Columns.Add("Errors");
            lvEvents.Columns.Add("Warnings");
            this.dbConn = dbConn;
            this.Model = Model;
            this.Text = "One-Line Audit: " + Model.FullClass + " (" + Model.ModelCategory + ")";
            cms.ItemClicked += new ToolStripItemClickedEventHandler(cms_ItemClicked);


            using (DbCommand dCmd = dbConn.CreateCommand("SELECT * FROM MM_DATABASE_ASSIGNMENT WHERE Model=:0", Model.ID))
            using (DbDataReader dRd = dCmd.ExecuteReader())
                while (dRd.Read())
                    Assignments.Add(new MM_Database_Assignment(dRd, dbConn, dbConn.Repository));
            lvEvents_ColumnClick(lvEvents, new ColumnClickEventArgs(2));
            lvEvents.AutoResizeColumns(ColumnHeaderAutoResizeStyle.ColumnContent);

        }

        /// <summary>
        /// Initialize a new one-line audit form
        /// </summary>
        /// <param name="User">The current user</param>
        /// <param name="dbConn">The database connection</param>
        public frmOneLineAudit(MM_Database_User User, MM_Database_Connector dbConn)
        {
            InitializeComponent();

            this.dbConn = dbConn;
            this.User = User;
            this.Text = "One-Line Audit: " + User.FullName;

            cms.ItemClicked += new ToolStripItemClickedEventHandler(cms_ItemClicked);
            //Build a list of all completed one-lines (whether with assignment or not) done by our user.                       
            lvEvents.Columns.Add("Element");
            lvEvents.Columns.Add("Model");
            lvEvents.Columns.Add("Completed on");
            lvEvents.Columns.Add("Errors");
            lvEvents.Columns.Add("Warnings");

            using (DbCommand dCmd = dbConn.CreateCommand("SELECT * FROM MM_DATABASE_ASSIGNMENT WHERE COMPLETEDBY=:0", User.ID))
            using (DbDataReader dRd = dCmd.ExecuteReader())
                while (dRd.Read())
                    Assignments.Add(new MM_Database_Assignment(dRd, dbConn, dbConn.Repository));
            lvEvents_ColumnClick(lvEvents, new ColumnClickEventArgs(2));
            lvEvents.AutoResizeColumns(ColumnHeaderAutoResizeStyle.ColumnContent);
        }

       

        /// <summary>
        /// Handle the column click by initiating a sort
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void lvEvents_ColumnClick(object sender, ColumnClickEventArgs e)
        {
            //Update our sorter
            if (Sorter == null)
                Sorter = new MM_Database_Assignment_Sorter(lvEvents.Columns[e.Column], false);
            else
            {
                Sorter.SortCol = lvEvents.Columns[e.Column];
                Sorter.Ascending = true;
            }
            Assignments.Sort(Sorter);

            List<ListViewItem> ToAdd = new List<ListViewItem>();
            lvEvents.Sorting = SortOrder.None;
            lvEvents.Items.Clear();
            foreach (MM_Database_Assignment Assignment in Assignments)
            {
                ListViewItem lvI = new ListViewItem();
                lvI.Text = Assignment.OneLineName;
                lvI.Name = "a" + Assignment.ID.ToString();
                lvI.ImageIndex = 0;
                //lvOneLines.Items.Add("a" + Assignemnt.ID.ToString(), Assignemnt.Model.Name, 0);
                lvI.Tag = Assignment;
                if (User != null)
                    lvI.SubItems.Add(Assignment.Model.Name);
                if (Model != null)
                {
                    lvI.SubItems.Add(Assignment.AssignedTo.Nickname);
                    if (Assignment.CompletedBy == null)
                        lvI.SubItems.Add("");
                    else
                        lvI.SubItems.Add(Assignment.CompletedBy.Nickname);
                }

                lvI.SubItems.Add(Assignment.AssignedOn.ToString());
                lvI.SubItems.Add(Assignment.Errors.ToString("#,##0"));
                lvI.SubItems.Add(Assignment.Warnings.ToString("#,##0"));
                if (Assignment.Errors > 0)
                    lvI.Group = lvEvents.Groups["Errors"];
                else
                    lvI.Group = lvEvents.Groups["Warnings"];
                lvEvents.Items.Add(lvI);
                ToAdd.Add(lvI);
            }
        }
        #endregion

        /// <summary>
        /// Bring up a menu for the user of validation options
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void lvEvents_MouseClick(object sender, MouseEventArgs e)
        {
            if (e.Button != MouseButtons.Right)
                return;
            ListViewHitTestInfo hti = (sender as ListView).HitTest(e.Location);
            if (hti.Item == null)
                return;
            cms.Tag = hti.Item.Tag;
            cms.Items.Clear();
            MM_Database_Assignment Assignment = hti.Item.Tag as MM_Database_Assignment;

            //Now, display information on our assignment
            cms.Items.Add("One-Line: " + Assignment.OneLineName).Enabled = false;
            cms.Items.Add("Model: " + Assignment.Model.Name).Enabled = false;
            cms.Items.Add("Completed on: " + Assignment.CompletedOn.ToString()).Enabled = false;
            cms.Items.Add("Completed by: " + Assignment.CompletedBy.Nickname).Enabled = false;
            cms.Items.Add("-");
            cms.Items.Add("Re-assign to me").Tag = User;
            ToolStripMenuItem UserList = cms.Items.Add("Re-assign to...") as ToolStripMenuItem;
            UserList.DropDownItemClicked +=new ToolStripItemClickedEventHandler(cms_ItemClicked);
            foreach (MM_Database_User UserToAdd in dbConn.Repository.User_Collection.Values)
            {
                ToolStripMenuItem NewItem = UserList.DropDownItems.Add(UserToAdd.Nickname) as ToolStripMenuItem;
                NewItem.Enabled = UserToAdd.UserState == MM_Database_User.enumUserState.Available;
                NewItem.Tag = UserToAdd;
            }


            //Retrieve all backups available
            SortedDictionary<DateTime, String> Backups = new SortedDictionary<DateTime, string>();
            using (DbCommand dCmd = dbConn.CreateCommand("SELECT SAVEDON, DOCUMENT FROM MM_ONELINE_BACKUP WHERE ONELINE=:0", Assignment.OneLine))
            using (DbDataReader dRd = dCmd.ExecuteReader())
                while (dRd.Read())
                    Backups.Add(Convert.ToDateTime(dRd["SavedOn"]), dRd["Document"].ToString());
            if (Backups.Count > 0)
            {
                ToolStripMenuItem BackupMenu = cms.Items.Add("Restore backup version...") as ToolStripMenuItem;
                BackupMenu.DropDownItemClicked += new ToolStripItemClickedEventHandler(cms_ItemClicked);
                foreach (KeyValuePair<DateTime, String> kvp in Backups)
                    BackupMenu.DropDownItems.Add(kvp.Key.ToString()).Tag = kvp.Value;
            }
            cms.Show(sender as Control, e.Location);
        }

        /// <summary>
        /// Handle a menu item click
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void cms_ItemClicked(object sender, ToolStripItemClickedEventArgs e)
        {
            MM_Database_Assignment Assignment;
            if (sender is ContextMenuStrip)
                Assignment = (sender as ContextMenuStrip).Tag as MM_Database_Assignment;
            else
                Assignment = ((sender as ToolStripMenuItem).Owner as ContextMenuStrip).Tag as MM_Database_Assignment;
            //If we pass a user, assign the one-line.
            if (e.ClickedItem.Tag is MM_Database_User && MessageBox.Show("Are you sure you would like to assign one-line " + Assignment.OneLineName + " to " + (e.ClickedItem.Tag as MM_Database_User).Nickname + "?", Application.ProductName, MessageBoxButtons.YesNo, MessageBoxIcon.Question) == DialogResult.Yes)
                using (DbCommand dCmd = dbConn.CreateCommand("UPDATE MM_DATABASE_ASSIGNMENT SET COMPLETEDON=NULL, COMPLETEDBY=NULL, USER=:0 WHERE ID=:1", (e.ClickedItem.Tag as MM_Database_User).ID, Assignment.ID))
                    dCmd.ExecuteNonQuery();
            else if (e.ClickedItem.Tag is String && MessageBox.Show("Are you suer you would like to restore a prior backup of one-line " + Assignment.OneLineName + "?", Application.ProductName, MessageBoxButtons.YesNo, MessageBoxIcon.Question) == DialogResult.Yes)
            {
                //First, retrieve the current XML for our oneline.
                String CurrXml;
                using (DbCommand dCmd = dbConn.CreateCommand("SELECT DOCUMENT FROM MM_DATABASE_ONELINE WHERE ID=:0", Assignment.OneLine))
                    CurrXml = dCmd.ExecuteScalar().ToString();

                //Then, update our one-line to make sure it's assigned.
                using (DbCommand dCmd = dbConn.CreateCommand("UPDATE MM_DATABASE_ASSIGNMENT SET COMPLETEDON=NULL, COMPLETEDBY=NULL, USER=:0 WHERE ID=:1", User.ID, Assignment.ID))
                    dCmd.ExecuteNonQuery();

                //Create a backup of our current XML
                using (DbCommand dCmd = dbConn.CreateCommand("INSERT INTO MM_ONELINE_BACKUP (ID, ONELINE, EDITEDBY, DOCUMENT, SAVEDON, MODEL) VALUES (SEQ_MM_ONELINE_BACKUP.NEXTVAL, :0, :1, :2, :3, :4)", Assignment.OneLine, User.ID, CurrXml, DateTime.Now, Assignment.Model.ID))
                    dCmd.ExecuteNonQuery();

                //Update our one-line's XML
                using (DbCommand dCmd = dbConn.CreateCommand("UPDATE MM_DATABASE_ONELINE SET DOCUMENT=:0 WHERE ID=:1", e.ClickedItem.Tag as string, Assignment.OneLine))
                    dCmd.ExecuteNonQuery();
            }

        }

        /// <summary>
        /// When our index changes, update accordingly
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void lvEvents_SelectedIndexChanged(object sender, EventArgs e)
        {

            lbDetails.Items.Clear();
            pbOneLine.Image = null;

            if (lvEvents.SelectedItems.Count == 1)
            {
                string InLine;
                MM_Database_Assignment SelAssignment = lvEvents.SelectedItems[0].Tag as MM_Database_Assignment;
                using (StringReader sRd = new StringReader(SelAssignment.Notes))
                    while ((InLine = sRd.ReadLine()) != null)
                        lbDetails.Items.Add(InLine);
                pbOneLine.Image = SelAssignment.OneLineImage;
            }
        }        
    }
}
